<template>
	<div class="container">
		<Breadcrumb :items="['menu.platform', 'menu.platform.role']" />
		<a-card class="general-card" :title="$t('menu.list.searchTable')">
			<a-row>
				<a-col :flex="1">
					<a-form :model="formModel" :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 18 }"
						label-align="left">
						<a-row :gutter="16">
							<a-col :span="8">
								<a-form-item field="roleId" :label="$t('role.form.roleId')">
									<a-input v-model="formModel.roleId"
										:placeholder="$t('role.form.roleId.placeholder')" />
								</a-form-item>
							</a-col>
							<a-col :span="8">
								<a-form-item field="roleName" :label="$t('role.form.roleName')">
									<a-input v-model="formModel.roleName"
										:placeholder="$t('role.form.roleName.placeholder')" />
								</a-form-item>
							</a-col>
							<a-col :span="8">
								<a-form-item field="menuId" :label="$t('role.form.menuId')">
									<a-select v-model="formModel.menuId" :options="menuSonOptions" />
								</a-form-item>
							</a-col>
						</a-row>
					</a-form>
				</a-col>
				<a-divider style="height: 84px" direction="vertical" />
				<a-col :flex="'86px'" style="text-align: right">
					<a-space direction="vertical" :size="18">
						<a-button type="primary" @click="search">
							<template #icon>
								<icon-search />
							</template>
							{{ $t('searchTable.form.search') }}
						</a-button>
						<a-button @click="reset">
							<template #icon>
								<icon-refresh />
							</template>
							{{ $t('searchTable.form.reset') }}
						</a-button>
					</a-space>
				</a-col>
			</a-row>
			<a-divider style="margin-top: 0" />
			<a-row style="margin-bottom: 16px">
				<a-col :span="12">
					<a-space>
						<a-button type="primary" @click="addHandleClick">
							<template #icon>
								<icon-plus />
							</template>
							{{ $t('searchTable.operation.create') }}
						</a-button>
					</a-space>
				</a-col>
				<a-col :span="12" style="display: flex; align-items: center; justify-content: end">
					<a-tooltip :content="$t('searchTable.actions.refresh')">
						<div class="action-icon" @click="search"><icon-refresh size="18" /></div>
					</a-tooltip>
					<a-dropdown @select="handleSelectDensity">
						<a-tooltip :content="$t('searchTable.actions.density')">
							<div class="action-icon"><icon-line-height size="18" /></div>
						</a-tooltip>
						<template #content>
							<a-doption v-for="item in densityList" :key="item.value" :value="item.value"
								:class="{ active: item.value === size }">
								<span>{{ item.name }}</span>
							</a-doption>
						</template>
					</a-dropdown>
					<a-tooltip :content="$t('searchTable.actions.columnSetting')">
						<a-popover trigger="click" position="bl" @popup-visible-change="popupVisibleChange">
							<div class="action-icon"><icon-settings size="18" /></div>
							<template #content>
								<div id="tableSetting">
									<div v-for="(item, index) in showColumns" :key="item.dataIndex" class="setting">
										<div style="margin-right: 4px; cursor: move">
											<icon-drag-arrow />
										</div>
										<div>
											<a-checkbox v-model="item.checked" @change="
                          handleChange($event, item as TableColumnData, index)
                        ">
											</a-checkbox>
										</div>
										<div class="title">
											{{ item.title === '#' ? '序列号' : item.title }}
										</div>
									</div>
								</div>
							</template>
						</a-popover>
					</a-tooltip>
				</a-col>
			</a-row>
			<a-table row-key="index" :loading="loading" :pagination="pagination"
				:columns="(cloneColumns as TableColumnData[])" :data="renderData.items" :bordered="false" :size="size"
				@page-change="onPageChange">
				<template #index="{ rowIndex }">
					{{ rowIndex + 1 + (pagination.current - 1) * pagination.pageSize }}
				</template>
				<template #type="{ record }">
					{{ record.type===1?'后台':'前台' }}角色
				</template>
				<template #operations="{record}">
					<a-button type="text" size="small" @click="updateHandleClick(record)">
						{{ $t('role.columns.operations.update') }}
					</a-button>
					<a-button type="text" size="small" @click="delHandleClick(record)">
						{{ $t('searchTable.columns.operations.del') }}
					</a-button>
				</template>
			</a-table>
		</a-card>
		<a-modal v-model:visible="addVisible" title="增加角色" @cancel="addHandleCancel" @before-ok="addHandleBeforeOk">
			<a-form :model="addRoleForm">
				<a-form-item field="roleName" label="角色名称" required>
					<a-input v-model="addRoleForm.roleName" placeholder="请输入角色名称" />
				</a-form-item>
				<a-form-item field="roleCode" label="角色代码" required>
					<a-input v-model="addRoleForm.roleCode" placeholder="请输入角色代码" />
				</a-form-item>
				<a-form-item field="description" label="角色介绍" required>
					<a-input v-model="addRoleForm.description" placeholder="请输入角色介绍" />
				</a-form-item>
				<a-form-item field="type" label="角色类型" required>
					<a-radio-group v-model="addRoleForm.type">
						<a-radio :value="1">后台</a-radio>
						<a-radio :value="2">前台</a-radio>
					</a-radio-group>
				</a-form-item>
			</a-form>
		</a-modal>
		<a-modal v-model:visible="updateVisible" title="更新权限" @cancel="updateHandleCancel"
			@before-ok="updateHandleBeforeOk">
			<a-tree :checkable="true" v-model:checked-keys="updateRoleForm.menuIds" :data="menuTreeOptions" />
		</a-modal>
		<a-modal :visible="delVisible" @ok="delHandleBeforeOk" @cancel="delHandleCancel" okText="确认" cancelText="取消"
			unmountOnClose>
			<template #title>
				是否删除
			</template>
			是否删除该角色,请注意:确保当前没有用户处于该角色下
		</a-modal>
	</div>
</template>

<script lang="ts" setup>
	import { computed, ref, reactive, watch, nextTick } from 'vue';
	import { useI18n } from 'vue-i18n';
	import useLoading from '@/hooks/loading';
	import { Message } from '@arco-design/web-vue';
	import { getSonMenu, MenuShow, searchRoleByPage, QueryRoleDto, delRole, MenuTree, getTreeMenu, getRoleMenu, updateRoleMenu, UpdateRoleMenuDto, addRole } from '@/api/platform';
	import { PageParams, PageResult, generatePageResult } from '@/types/page';
	import { Pagination } from '@/types/global';
	import type { SelectOptionData } from '@arco-design/web-vue/es/select/interface';
	import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
	import cloneDeep from 'lodash/cloneDeep';
	import Sortable from 'sortablejs';
	import { done } from 'nprogress';

	type SizeProps = 'mini' | 'small' | 'medium' | 'large';
	type Column = TableColumnData & { checked ?: true };

	const addVisible = ref(false);
	const updateVisible = ref(false);
	const delVisible = ref(false);

	const generateFormModel = () => {
		return {
			menuId: -1,
			roleId: null,
			roleName: ""
		};
	};
	const { loading, setLoading } = useLoading(true);
	const { t } = useI18n();
	const renderData = ref(generatePageResult());
	const formModel = ref(generateFormModel());
	const cloneColumns = ref<Column[]>([]);
	const showColumns = ref<Column[]>([]);
	const sonMenuList = ref<MenuShow[]>(new Array(7).fill({}));
	const menuTreeList = ref<SelectOptionData[]>(new Array(7).fill({}));
	const size = ref<SizeProps>('medium');
	const basePagination : Pagination = {
		current: 1,
		pageSize: 30,
	};
	const pagination = reactive({
		...basePagination,
	});
	const addRoleForm = reactive({
		roleName: "",
		roleCode: "",
		description: "",
		type: 1
	})
	const updateRoleForm = reactive({
		roleId: 0,
		menuIds: []
	})
	const deleteRoleId = {
		type: 0,
		roleId: 0
	};
	const densityList = computed(() => [
		{
			name: t('searchTable.size.mini'),
			value: 'mini',
		},
		{
			name: t('searchTable.size.small'),
			value: 'small',
		},
		{
			name: t('searchTable.size.medium'),
			value: 'medium',
		},
		{
			name: t('searchTable.size.large'),
			value: 'large',
		},
	]);
	const columns = computed<TableColumnData[]>(() => [
		{
			title: t('role.columns.id'),
			dataIndex: 'id',
		},
		{
			title: t('role.columns.roleName'),
			dataIndex: 'roleName',
		},
		{
			title: t('role.columns.roleCode'),
			dataIndex: 'roleCode',
		},
		{
			title: t('role.columns.description'),
			dataIndex: 'description',
		},
		{
			title: t('role.columns.type'),
			dataIndex: 'type',
			slotName: 'type',
		},
		{
			title: t('role.columns.updateTime'),
			dataIndex: 'updateTime',
		},
		{
			title: t('searchTable.columns.operations'),
			dataIndex: 'operations',
			slotName: 'operations',
		},
	]);
	const getSonMenuList = async () => {
		try {
			const { data } = await getSonMenu();
			data.unshift({
				id: -1,
				menuName: "全部"
			})
			sonMenuList.value = data;
		} catch (err) {
			// you can report use errorHandler or other
		} finally {
			setLoading(false);
		}
	}
	const getTreeMenuOptions = async () => {
		try {
			const { data } = await getTreeMenu();
			menuTreeList.value = data;
		} catch (err) {
			// you can report use errorHandler or other
		} finally {
			setLoading(false);
		}
	}
	getTreeMenuOptions();
	const menuTreeOptions = computed<SelectOptionData[]>(() => {
		return menuTreeList.value;
	});
	getSonMenuList();
	const menuSonOptions = computed<SelectOptionData[]>(() => {
		return Array.from(sonMenuList.value).map((menu) => {
			return {
				label: menu.menuName,
				value: menu.id
			};
		})
	});
	const fetchData = async (
		params : PageParams = { current: 1, pageSize: 30 }
	) => {
		setLoading(true);
		try {
			const { data } = await searchRoleByPage(params, formModel.value as unknown as QueryRoleDto);
			renderData.value.items = data.items;
			pagination.current = params.current;
			pagination.total = data.counts;
		} catch (err) {
			// you can report use errorHandler or other
		} finally {
			setLoading(false);
		}
	};
	const addHandleClick = () => {
		addRoleForm.roleName = "";
		addRoleForm.roleCode = "";
		addRoleForm.description = "";
		addRoleForm.type = 1;
		addVisible.value = true;
	};
	const delHandleClick = (record : any) => {
		deleteRoleId.type = record.type;
		deleteRoleId.roleId = record.id;
		delVisible.value = true;
	};
	const addHandleCancel = () => {
		addVisible.value = false;
	};
	const updateHandleCancel = () => {
		updateVisible.value = false;
	};
	const updateHandleClick = async (record : any) => {
		updateRoleForm.roleId = record.id;
		const { data } = await getRoleMenu({ roleId: record.id });
		updateRoleForm.menuIds = data as never[];
		updateVisible.value = true;
	};
	const updateHandleBeforeOk = () => {
		updateRoleMenu({ roleId: updateRoleForm.roleId, menuIds: updateRoleForm.menuIds.toString() });
		updateVisible.value = false;
		return true;
	};
	const addHandleBeforeOk = () => {
		if (addRoleForm.roleName == null || addRoleForm.roleName === "" ||
			addRoleForm.roleCode == null || addRoleForm.roleCode === "" ||
			addRoleForm.roleCode == null || addRoleForm.roleCode === "") {
			Message.error("缺少内容")
			return true;
		}

		try {
			const res = addRole(addRoleForm);
			Message.success(t('role.form.modal.create.success'));
		} catch (err) {
			Message.error(t('role.form.modal.create.fail'))
			throw err;
		}
		console.log(addRoleForm);
		addVisible.value = false;
		return true;
	};
	const delHandleBeforeOk = () => {
		try {
			const res = delRole(deleteRoleId)
		} catch (err) {
			delVisible.value = false;
			throw err;
		}
		delVisible.value = false;
		return true;
	};
	const delHandleCancel = () => {
		delVisible.value = false;
	};

	const search = () => {
		fetchData({
			...basePagination,
			...formModel.value,
		} as unknown as PageParams);
	};
	const onPageChange = (current : number) => {
		fetchData({ ...basePagination, current });
	};

	fetchData();
	const reset = () => {
		formModel.value = generateFormModel();
	};

	const handleSelectDensity = (
		val : string | number | Record<string, any> | undefined,
		e : Event
	) => {
		size.value = val as SizeProps;
	};

	const handleChange = (
		checked : boolean | (string | boolean | number)[],
		column : Column,
		index : number
	) => {
		if (!checked) {
			cloneColumns.value = showColumns.value.filter(
				(item) => item.dataIndex !== column.dataIndex
			);
		} else {
			cloneColumns.value.splice(index, 0, column);
		}
	};

	const exchangeArray = <T extends Array<any>>(
		array : T,
		beforeIdx : number,
		newIdx : number,
		isDeep = false
	) : T => {
		const newArray = isDeep ? cloneDeep(array) : array;
		if (beforeIdx > -1 && newIdx > -1) {
			// 先替换后面的，然后拿到替换的结果替换前面的
			newArray.splice(
				beforeIdx,
				1,
				newArray.splice(newIdx, 1, newArray[beforeIdx]).pop()
			);
		}
		return newArray;
	};

	const popupVisibleChange = (val : boolean) => {
		if (val) {
			nextTick(() => {
				const el = document.getElementById('tableSetting') as HTMLElement;
				const sortable = new Sortable(el, {
					onEnd(e : any) {
						const { oldIndex, newIndex } = e;
						exchangeArray(cloneColumns.value, oldIndex, newIndex);
						exchangeArray(showColumns.value, oldIndex, newIndex);
					},
				});
			});
		}
	};

	watch(
		() => columns.value,
		(val) => {
			cloneColumns.value = cloneDeep(val);
			cloneColumns.value.forEach((item, index) => {
				item.checked = true;
			});
			showColumns.value = cloneDeep(cloneColumns.value);
		},
		{ deep: true, immediate: true }
	);
</script>

<script lang="ts">
	export default {
		name: 'RoleInfo',
	};
</script>

<style scoped lang="less">
	.container {
		padding: 0 20px 20px 20px;
	}

	:deep(.arco-table-th) {
		&:last-child {
			.arco-table-th-item-title {
				margin-left: 16px;
			}
		}
	}

	.action-icon {
		margin-left: 12px;
		cursor: pointer;
	}

	.active {
		color: #0960bd;
		background-color: #e3f4fc;
	}

	.setting {
		display: flex;
		align-items: center;
		width: 200px;

		.title {
			margin-left: 12px;
			cursor: pointer;
		}
	}
</style>